﻿/*  ----------------------------------------------------------------------------
 *  Copyright somemorebytes 2010
	DavidP.
	somemorebytes@gmail.com
 *  ----------------------------------------------------------------------------
 *  Simple EXIF Renamer
 *  ----------------------------------------------------------------------------
 *  File:       Mainform.cs
 *  ----------------------------------------------------------------------------


This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;

namespace SimpleExifRenamer
{


   
    public partial class MainForm : Form
    {

        //Renamer
        private Renamer ren;

        //Property to change the progressbar value
        public decimal ProgressBarValue { set { this.refreshPRogressBar(value); } }

        public MainForm()
        {
            InitializeComponent();


            this.initialize();
        }

        //initialize the dialog
        private void initialize()
        {

            //initialize the renamer
            this.ren = new Renamer();
            
            //Give the renamer a reference to the GUI
            this.ren.gui = this;

            //Initialize pictureboxes
            this.pictureBoxNo.Visible = false;
            this.pictureBoxYes.Visible = true;

            //initialize tooltips
            this.initializeHelpToolTips();

            //Initialize Comboboxes
            this.initializeComboBoxes();

            //Initialize textboxes
            this.initializeTextBoxes();

            //Allow Drag and Drop in the picture box
            this.pictureTarget.AllowDrop = true;

            //Initialize progressbar values
            this.progressBarRun.Maximum = 100;

                        
        }

        //Fill comboboxes with default renaming patterns
        private void initializeComboBoxes()
        {

            List<string> patt = this.ren.getPatterns();

            this.comboBoxPattern.DataSource = patt;
            
            //Default selection
            this.comboBoxPattern.SelectedIndex = 0;

        }

        //initialize tooltips
        private void initializeHelpToolTips()
        {
            ToolTip Tip1 = new ToolTip();
            Tip1.AutoPopDelay = 15000;
            Tip1.UseAnimation = true;
            Tip1.UseFading = true;
            Tip1.ToolTipIcon = ToolTipIcon.Info;
            Tip1.IsBalloon = true;
            Tip1.ShowAlways = true;
            Tip1.ToolTipTitle = "Root Target Directory";
            string message1 = "This is the directory where Simple Exif Renamer will output the renamed pictures.";
            Tip1.SetToolTip(this.textBoxTargetDir, message1);

            ToolTip Tip2 = new ToolTip();
            Tip2.AutoPopDelay = 15000;
            Tip2.UseAnimation = true;
            Tip2.UseFading = true;
            Tip2.ToolTipIcon = ToolTipIcon.Info;
            Tip2.IsBalloon = true;
            Tip2.ShowAlways = true;
            Tip2.ToolTipTitle = "Year Subfolder";
            string message2 = "If checked, Simple Exif Renamer will create a different subfolder folder for each year and will sort the pictures by year.";
            Tip2.SetToolTip(this.checkBoxYear, message2);

            ToolTip Tip3 = new ToolTip();
            Tip3.AutoPopDelay = 15000;
            Tip3.UseAnimation = true;
            Tip3.UseFading = true;
            Tip3.ToolTipIcon = ToolTipIcon.Info;
            Tip3.IsBalloon = true;
            Tip3.ShowAlways = true;
            Tip3.ToolTipTitle = "Month Subfolder";
            string message3 = "If checked, Simple Exif Renamer will create a different subfolder folder for each month and will sort the pictures by month.";
            Tip3.SetToolTip(this.checkBoxMonth, message3);

            ToolTip Tip4 = new ToolTip();
            Tip4.AutoPopDelay = 15000;
            Tip4.UseAnimation = true;
            Tip4.UseFading = true;
            Tip4.ToolTipIcon = ToolTipIcon.Info;
            Tip4.IsBalloon = true;
            Tip4.ShowAlways = true;
            Tip4.ToolTipTitle = "Rename Pattern Selection";
            string message4 = "The rename pattern will be converted to you final picture name.\nYou can use the tags listed below, and they will be replaced in the process.\nEverything else, will be part of the picture name.\n\nExample:\n Ibiza({Year}-{Month})[{Hour}{Minute}] will produce Ibiza(2009-12-21)[2145].jpg\n\nNOTE: Use as many tags as possible, to avoid duplicate names.";
            Tip4.SetToolTip(this.comboBoxPattern, message4);

            ToolTip Tip5 = new ToolTip();
            Tip5.AutoPopDelay = 15000;
            Tip5.UseAnimation = true;
            Tip5.UseFading = true;
            Tip5.ToolTipIcon = ToolTipIcon.Info;
            Tip5.IsBalloon = true;
            Tip5.ShowAlways = true;
            Tip5.ToolTipTitle = "Move pictures";
            string message5 = "When checked, Simple Exif Renamer will move the pictures after renaming them instead of copy them.\nThis will make the process faster and will required less disk space, but it is NOT recommended unless you know what you're doing!.";
            Tip5.SetToolTip(this.checkBoxMove, message5);

            ToolTip Tip6 = new ToolTip();
            Tip6.AutoPopDelay = 15000;
            Tip6.UseAnimation = true;
            Tip6.UseFading = true;
            Tip6.ToolTipIcon = ToolTipIcon.Info;
            Tip6.IsBalloon = true;
            Tip6.ShowAlways = true;
            Tip6.ToolTipTitle = "Check File Names";
            string message6 = "When checked, Simple Exif Renamer will check EVERY file name for invalid characters.\n\nSometimes, due to picture corruption, invalid ascii chars can be found on the EXIF data.This will remove them.\n\nUse ONLY if you are having problems!.\nThis option will make the process MUCH slower!!!";
            Tip6.SetToolTip(this.checkBoxFailsafeRen, message6);
        }

        //Initialize TextBoxes
        private void initializeTextBoxes()
        {
            this.textBoxTargetDir.Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Output");

        }

        //Change the value of the progressbar.
        //This is a tricky one. We want to change it from another thread, so we need to do it through a delegate.
        private void refreshPRogressBar(decimal val)
        {
            if (InvokeRequired)
            {
                RefreshProgressBarDelegate del = new RefreshProgressBarDelegate(refreshPRogressBar);
                this.Invoke(del, val);
            }
            else
            {
                this.progressBarRun.Value = (int)val;
            }
        }
       
        //Browse for a target directory
        private void buttonBrowse_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            dlg.RootFolder = Environment.SpecialFolder.Desktop;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                this.textBoxTargetDir.Text = Path.Combine(dlg.SelectedPath,"Output");
            }
        }

        //Clear the processqueue
        private void buttonClear_Click(object sender, EventArgs e)
        {
            //Clear the queues
            this.ren.clearQueues();
            //Update the label
            this.labelNumberFiles.Text = this.ren.processQueue.Count.ToString();
        }

        //Close the application
        private void buttonExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

   
        //Start the renaming process!!!!
        private void buttonLaunch_Click(object sender, EventArgs e)
        {

            if (!this.ren.ProcessRunning)
            {
                string patt = this.comboBoxPattern.Text;

                //Check that the pattern is correct
                if (!(this.ren.testPattern(patt)))
                {
                    MessageBox.Show("The pattern that you selected is invalid. File names can't contain any of these characters:\n / \\ * ? \" < > |", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                this.ren.renamePattern = patt;

                //The target dir must exist
                if (!(System.IO.Directory.Exists(this.textBoxTargetDir.Text)))
                {
                    if (MessageBox.Show("The root target folder does not exist. Do you want to create it?.", "Target Folder Not Found", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        try
                        {
                            System.IO.Directory.CreateDirectory(this.textBoxTargetDir.Text);
                        }
                        catch
                        {
                            MessageBox.Show("Couldn't create target directory", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return;
                        }
                    }
                    else
                    {
                        return;
                    }
                    
                }

                //options
                this.ren.yearSubDir = this.checkBoxYear.Checked;
                this.ren.monthSubDir = this.checkBoxMonth.Checked;
                this.ren.rootTargetDir = this.textBoxTargetDir.Text;
                this.ren.movefiles = this.checkBoxMove.Checked;
                this.ren.checkFilename = this.checkBoxFailsafeRen.Checked;

                //Go GO Go!!!
               try 
               {
                  
                    this.ren.startProcessing();
                    this.buttonLaunch.BackgroundImage = SimpleExifRenamer.Properties.Resources.stop;
                }
                catch (Exception w)
                {
                    this.treatException(w);
                }

            }
            else //The process is running, so we are killing it
            {
                if (MessageBox.Show("Are you sure you want to stop the process?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    try
                    {
                        //Finish him!!!
                        this.ren.stopProcessing();

                    }
                    catch (Exception w)
                    {
                        MessageBox.Show("An error ocurred while trying to stop processing the pictures.\nOriginal error text:\n\n" + w.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        return;
                    }

                    if (MessageBox.Show("The process has not been fully completed. Do you want to delete the target folder [" + this.ren.rootTargetDir + "] before continue?", "Delete files?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        if(Directory.Exists(this.ren.rootTargetDir))
                        {
                            System.IO.Directory.Delete(this.ren.rootTargetDir, true);
                        }
                    }

                    //Update teh GUI
                    this.processFinishedUpdateGUI(false);

                }
                             
            }
        }

        //Update the GUI when the process has finished.
        public void processFinishedUpdateGUI(bool cleanfinish)
        {
            //Same thread!
            if (InvokeRequired)
            {
                FinishProcessDelegate del = new FinishProcessDelegate(processFinishedUpdateGUI);
                this.Invoke(del, true);
            }
            else
            {

                //Change the picture again
                this.buttonLaunch.BackgroundImage = SimpleExifRenamer.Properties.Resources.launch2;

                this.ProgressBarValue = 0;
               
                if (cleanfinish)
                {
                    int numberProcessed = this.ren.processQueue.Count;
                    int numberNoDate = this.ren.noDateQueue.Count;
                    int numberError = this.ren.errorQueue.Count;
                    int numberNoPicture = this.ren.noPictures.Count;
                    int numberNotProcessed = this.ren.notProcessed.Count;

                    string message = "Process Complete!\n\nTotal Processed Files: " + numberProcessed.ToString() + "\nFiles with no EXIF date: " + numberNoDate.ToString() + "\nFiles that produced errors: " + numberError.ToString() + "\nOther media (Not jpg): " + numberNoPicture.ToString() + "\nFiles Skipped (not supported): " + numberNotProcessed.ToString();

                    if (numberError > 0)
                    {
                        if (numberError <= 10)
                        {
                            message += "\n\nError Listing:\n";

                            foreach (string s in this.ren.errorQueue)
                            {
                                message += s + "\n";
                            }

                        }
                        else
                        {
                            message += "\n\nThere were too many errors to list them here!!! ";
                        }
                    }

                    MessageBox.Show(message, "Done", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);

                    //Reset the queues
                    this.ren.clearQueues();
                    this.labelNumberFiles.Text = "0";
                }
            }

          
        }

        

        //Shows a message IN THE MAIN THREAD to treat an exception thrown from the process thread.
        public void treatException(Exception w)
        {
            if (InvokeRequired)
            {
                TreatException del = new TreatException(treatException);
                this.Invoke(del, w);
            }
            else
            {
                MessageBox.Show("An error ocurred while processing the pictures.\nOriginal error text:\n\n" + w.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

                if (MessageBox.Show("The process has not been fully completed. Do you want to delete the target folder [" + this.ren.rootTargetDir + "] before continue?", "Delete files?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    System.IO.Directory.Delete(this.ren.rootTargetDir, true);
                }
                this.processFinishedUpdateGUI(false);
              
            }

        }

        //Check if the pattern has invalid characters
        private void comboBoxPattern_TextChanged(object sender, EventArgs e)
        {
            //Check that the pattern is correct
            if (!(this.ren.testPattern(this.comboBoxPattern.Text)))
            {
                this.pictureBoxNo.Visible = true;
                this.pictureBoxYes.Visible = false;
                return;
            }
            this.pictureBoxNo.Visible = false;
            this.pictureBoxYes.Visible = true;
        }
        
        //OnDragEnter
        private void pictureTarget_DragEnter(object sender, DragEventArgs e)
        {

            //Check available effects of the dragged object, and set the actual effect to "Copy"
            e.Effect = DragDropEffects.Copy;
            if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
            {
                //If the files can be added, cnage the image
                this.pictureTarget.Image = SimpleExifRenamer.Properties.Resources.plus;
            }
            
        }

        //OnDragLeave
        private void pictureTarget_DragLeave(object sender, EventArgs e)
        {
            //when the cursor leaves the picturebox, change the picture again to the target
            this.pictureTarget.Image = SimpleExifRenamer.Properties.Resources.target;
        }

        //OnDragDrop
        private void pictureTarget_DragDrop(object sender, DragEventArgs e)
        {
            //If the object dragged contains files
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
                {
                    //Extract the filenames
                    string[] fileNames = (string[])e.Data.GetData(DataFormats.FileDrop);

                    //Add each dragged file/directory to processQueue
                    for (int i = 0; i < fileNames.Length; i++)
                    {
                        string path = fileNames[i];

                        //Check if it's a directory or a file and process it
                        FileAttributes att = File.GetAttributes(path);

                        try
                        {
                            if ((att & FileAttributes.Directory) == FileAttributes.Directory)
                            {
                                //It's a folder
                                this.ren.addFolderRecursive(path);
                            }
                            else
                            {
                                //It's a file
                                this.ren.addFile(path);
                            }
                        }
                        catch(Exception w)
                        {
                            MessageBox.Show("A problem occurred while reading the file/folder) "+ path + ".\nOriginal error Message: " + w.Message +"\n\nIt's probably a good idea to clear the added files queue and start over once you solved the problem.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            return;
                        }

                        

                    }
                }
            }

            //Restore the picture
            this.pictureTarget.Image = SimpleExifRenamer.Properties.Resources.target;
           
            //Update the counter
            //this.labelNumberFiles.Text=this.ren.processQueue.Count.ToString();
            this.labelNumberFiles.Text=(this.ren.processQueue.Count + this.ren.noPictures.Count + this.ren.notProcessed.Count).ToString();
        }

        //When the form closes, we need to be sure we don't leave any thread around
        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.ren.stopProcessing();
        }

        private void buttonAbout_Click(object sender, EventArgs e)
        {
            FormAbout dlg = new FormAbout();
            dlg.ShowDialog();
        }


    }
}